package com.evangelion.lock;

import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.locks.LockSupport;

public class EvangelionvrLock {

    private volatile int state = 0;    //0为无锁状态

    /**
     * ★当前持有锁的线程
     * -于
     */
    private Thread lockHolder;

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }

    public Thread getLockHolder() {
        return lockHolder;
    }

    public void setLockHolder(Thread lockHolder) {
        this.lockHolder = lockHolder;
    }

    private ConcurrentLinkedQueue<Thread> queue = new ConcurrentLinkedQueue<>();

    private boolean tryAquire() {
        int state = getState();
        Thread t = Thread.currentThread();
        if (state == 0) {
            if ((queue.size() == 0 || t == queue.peek()) &&compareAndSwapState(0, 1)) {
                setLockHolder(t);
                return true;
            }
        }
        return false;
    }


    public void lock() {
        //1.获取锁-CAS-compareAndSwap
        if (tryAquire()) {
            return;
        }

        //2.停留在当前方法
        Thread currentThread = Thread.currentThread();
        //加锁失败，放入队列中等待
        queue.add(currentThread);
        for (; ; ) {
            //自旋会相当浪费资源
            //peek是拿一下队头，但是不会移除
            if (queue.peek() == currentThread && tryAquire()) {
                System.out.println("hold lock Thread-name" + currentThread.getName());
                queue.poll(); //从队列中移除
                return;
            }
            LockSupport.park(currentThread);
        }
        //3.锁被释放后，再次获取锁
    }

    public void unlock(){
        Thread currentThread = Thread.currentThread();
        if (Thread.currentThread() != lockHolder) {
            throw new RuntimeException("你不是持有锁的线程，不可以释放锁");
        }

        int state = getState();

        if( compareAndSwapState(1,0)) {
            System.out.println(String.format("Thread-name:%s,释放锁成功",currentThread.getName()));
            setLockHolder(null);
            Thread handThread = queue.peek();
            if(handThread !=null) {
                LockSupport.unpark(handThread);  //线程被唤醒
            }
        }
    }


    private static final Unsafe unsafe = initUnsafe();
    private static final long stateOffset;

    private static Unsafe initUnsafe(){
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            return (Unsafe) f.get(null);
        } catch (Exception e) {
            e.printStackTrace();
            //log.error(e.getMessage(),e);
            return null;
        }
    }

    /**
     * 原子操作
     * Oparam o1dValue
     * oldvalue:线程I作内存当中的值
     * param
     * newvalue:要替换的新值
     *
     * @return
     **/
    public final boolean compareAndSwapState(int oldValue, int newValue) {
        return unsafe.compareAndSwapInt(this, stateOffset, oldValue, newValue);
    }


    static {
        try {
            stateOffset = unsafe.objectFieldOffset(EvangelionvrLock.class.getDeclaredField("state"));
        } catch (Exception e) {
            throw new Error();
        }

    }


}
